/****************************************************************************
**
** Copyright (C) 2009-2010 Mist Poryvaev.
** All rights reserved.
** Contact: Mist Poryvaev (mist.poryvaev@gmail.com)
**
** This file is part of the RailWorm project.
**
****************************************************************************/

#include "connectrzd.h"
#include <QtGui>

QMap <QString, QByteArray> HttpTools::g_Queries;
QString HttpTools::g_ProxyAddress, HttpTools::g_ProxyPort;

// -----------------------------------------

void OpenUrlThread::start(QUrl Url) {
	if (isRunning()) {
		return;
	}
	m_Url = Url;
	QThread::start();
}

void OpenUrlThread::run() {
	QDesktopServices::openUrl(m_Url);
	deleteLater();
}

// -----------------------------------------

ResponseHandler::ResponseHandler(const QNetworkRequest & Header, int _Encoding, int Id, const QByteArray & Data): QObject() {

	m_Header = Header;
	m_Encoding = _Encoding;
	m_Id = Id;
	m_Data = Data;
	m_Url = Header.url();
	g_Responses[m_Id] = this;

	MakeRequest();
}

ResponseHandler::~ResponseHandler() {
	g_Responses.remove(m_Id);
	m_Reply->deleteLater();
}

QNetworkReply * ResponseHandler::Reply(int _Id) {
	if (g_Responses.contains(_Id) == false) {
		return 0;
	}
	return g_Responses[_Id]->m_Reply;
}

void ResponseHandler::MakeRequest() {
	m_Reply = g_NetworkManager.get(m_Header);
//	m_Reply = g_NetworkManager.post(m_Header, QByteArray());
	m_Reply->ignoreSslErrors();
	connect(m_Reply, SIGNAL(finished()), this, SLOT(OnPageRequestFinished()));
	connect(m_Reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(OnPageError(QNetworkReply::NetworkError)));
	connect(m_Reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(OnPageSslErrors(QList<QSslError>)));
}

void ResponseHandler::OnPageRequestFinished() {
	if (m_Reply->error() != QNetworkReply::NoError) {
		qDebug() << "Finished with error, id =" << QString::number(m_Id) << ", " << m_Reply->errorString();
		emit PageRequestFinished(m_Reply->errorString(), m_Id, true);
		return;
	}
	qDebug() << "Finished, id =" << QString::number(m_Id);
	qDebug() << "Status: " << m_Reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray();
	QString Response = HttpTools::Extract(m_Reply, static_cast<HttpTools::Encoding>(m_Encoding));
	qDebug() << "Response extracted.";
	if (Response.isEmpty()) {
		QUrl url = m_Reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
		g_Responses.remove(m_Id);
		m_Reply->deleteLater();

		if (url.isEmpty() == false) {
			qDebug() << "redirect to url " << url.toString();
			m_Header.setUrl(url);
		}

		MakeRequest();

		qDebug() << "Response is empty, id =" << QString::number(m_Id);
		qDebug() << "Restart request";

		g_Responses[m_Id] = this;

		return;
	}
	emit PageRequestFinished(Response, m_Id, false);
	deleteLater();
}

void ResponseHandler::OnPageError(QNetworkReply::NetworkError code) {

}

void ResponseHandler::OnPageSslErrors(QList<QSslError> errors) {
	foreach (QSslError _error, errors) {
		qDebug() << _error.errorString();
	}
}

QNetworkAccessManager ResponseHandler::g_NetworkManager;
QMap<int, ResponseHandler *> ResponseHandler::g_Responses;

// -----------------------------------------

int HttpTools::g_Id = 0;

void HttpTools::OpenUrl(QUrl Url) {
	qDebug() << "OpenUrl " << Url.toString();
	OpenUrlThread * _thread = new OpenUrlThread();
	_thread->start(Url);
}

int HttpTools::Request(QString _Host, QByteArray Data, Type _Type, Encoding _Encoding, QObject * Receiver, const char * Slot) {
	QByteArray TypeStr;
	if (_Type == HttpTools::Form) {
		TypeStr = "application/x-www-form-urlencoded";
	}
	else {
		TypeStr = "text/html";
	}
	if ((g_ProxyAddress.isEmpty() == false) && (g_ProxyPort.toInt() > 0)) {
		ResponseHandler::g_NetworkManager.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, g_ProxyAddress, g_ProxyPort.toInt()));
	}
	else {
		ResponseHandler::g_NetworkManager.setProxy(QNetworkProxy::NoProxy);
	}
	if (_Host.isEmpty()) {
		_Host = PassHost();
	}
	QNetworkRequest Request;
	Request.setRawHeader("Host", QUrl(_Host).host().toLocal8Bit());
	Request.setRawHeader("User-Agent", "RailWorm");
	Request.setHeader(QNetworkRequest::ContentTypeHeader, TypeStr);
	Request.setHeader(QNetworkRequest::ContentLengthHeader, 0);
	if (_Host.contains("://") == false) {
		_Host = "http://" + _Host;
	}
	if (_Host.contains("https://")) {
		Request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
	}
	Data = _Host.toLocal8Bit() + Data;
	Request.setUrl(QString::fromUtf8(Data));
//	QUrl url;
//	url.setEncodedUrl(Data);
//	Request.setUrl(url);
	qDebug() << "url " << Request.url().toString();

	int Id = g_Id++;
	if (Receiver && Slot) {
		connect(
				new ResponseHandler(Request, _Encoding, Id, Data),
				SIGNAL(PageRequestFinished(QString,int,bool)),
				Receiver,
				Slot);
	}
	return Id;
}

QString HttpTools::Extract(QNetworkReply * Reply, Encoding _Encoding) {
	if (Reply == 0) {
		qDebug() << "extract - bad reply";
		return "";
	}
	if (Reply->bytesAvailable() == 0) {
		qDebug() << "extract - size = 0";
		return "";
	}
	QByteArray _Bytes = Reply->readAll();
	for (char _c = 0; _c < ' '; _c++) {
		if (_c != '\n') {
			_Bytes.replace(_c, "");
		}
	}
	if (_Encoding == HttpTools::Utf8) {
		return QString::fromUtf8((_Bytes + "\0").data());
	}
	return QString::fromLocal8Bit((_Bytes + "\0").data());
}

QString HttpTools::PassHost() {
	return "pass.rzd.ru";
}

QString HttpTools::TicketHost() {
	return "ticket.rzd.ru";
}

void HttpTools::AddQuery(const QString & Name, QByteArray Data) {
	g_Queries.insert(Name, Data);
}

void HttpTools::RemoveQuery(const QString & Name) {
	g_Queries.remove(Name);
}

QByteArray HttpTools::Query(const QString & Name) {
	return g_Queries.value(Name, QByteArray());
}

void HttpTools::SetProxy(QString Address, QString Port) {
	g_ProxyAddress = Address;
	g_ProxyPort = Port;
}


